package com.adamfass.tractorbeam;

import com.jme.bounding.BoundingSphere;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.MaterialState.MaterialFace;
import com.jme.system.DisplaySystem;
import com.jmex.physics.PhysicsSpace;

public class FlyingSaucer extends PhysicsGameObject {
  private static final float MASS = 20;
  private static final float THRUST = 12000;
  private static final float DRAG = 4;
  private static final float REVERSE_THRUST = 2;
  
  private final ColorRGBA color;
  private final Controller controller;
  private final GameObjectManager gameObjectManager;
  private final Node rootNode;
  
  private PhysicsGameObject currentTarget;
  
  public FlyingSaucer(Node rootNode, PhysicsSpace physicsSpace, 
                      Vector3f worldTranslation, ColorRGBA color,
                      Controller controller, 
                      GameObjectManager gameObjectManager) {
    super(physicsSpace);
    
    this.rootNode = rootNode;
    this.color = color;
    this.gameObjectManager = gameObjectManager;
    
    physicsNode.createSphere("flying saucer physics sphere");
    physicsNode.setLocalTranslation(worldTranslation);
    physicsNode.setLocalScale(25);
    physicsNode.setMass(MASS);
    physicsNode.updateGeometricState(0, true);
    
    rootNode.attachChild(physicsNode);
    
    Sphere disc = new Sphere("saucer disc " + color, 10, 20, 1);    
    disc.setLocalScale(new Vector3f(1, 0.25f, 1));
    physicsNode.attachChild(disc);
    
    final MaterialState discMaterialState = 
      DisplaySystem.getDisplaySystem().getRenderer().createMaterialState();
    discMaterialState.setEnabled(true);
    discMaterialState.setDiffuse(color);
    discMaterialState.setAmbient(color);
    disc.setRenderState(discMaterialState);
    
    Sphere bubble = new Sphere("saucer bubble", 10, 10, 0.4f);
    bubble.setLocalTranslation(0, 0.25f, 0);
    physicsNode.attachChild(bubble);
    bubble.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
    final MaterialState bubbleMaterialState = 
      DisplaySystem.getDisplaySystem().getRenderer().createMaterialState();
    bubbleMaterialState.setEnabled(true);
    bubbleMaterialState.setAmbient(new ColorRGBA(0.5f, 0.5f, 1, 0.3f));
    bubbleMaterialState.setDiffuse(new ColorRGBA(0.5f, 0.5f, 1, 0.3f));
    bubbleMaterialState.setSpecular(new ColorRGBA(1, 1, 1, 0.3f));
    bubbleMaterialState.setShininess(10);
    bubbleMaterialState.setMaterialFace(MaterialFace.FrontAndBack);
    bubble.setRenderState(bubbleMaterialState);
    
    final BlendState bubbleBlendState = 
      DisplaySystem.getDisplaySystem().getRenderer().createBlendState();
    bubbleBlendState.setBlendEnabled(true);
    bubbleBlendState.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
    bubbleBlendState.setDestinationFunction(BlendState.DestinationFunction.One);
    bubbleBlendState.setTestEnabled(true);
    bubbleBlendState.setTestFunction(BlendState.TestFunction.GreaterThan);
    bubbleBlendState.setEnabled(true);
    bubble.setRenderState(bubbleBlendState);
    
    this.controller = controller;
    
    physicsNode.updateGeometricState(0, true);
    
    physicsNode.setModelBound(new BoundingSphere());
    physicsNode.updateModelBound();
  }
  
  // TODO(afass): Move this logic to ThrustGameUpdateLogic.java
  public void update() {
    super.update();
    
    Vector3f controllerThrustVector = controller.getThrustVector();
    
    // Thrust
    physicsNode.addForce(controllerThrustVector.mult(THRUST));
    
    // Drag
    physicsNode.addForce(physicsNode.getLinearVelocity(null).multLocal(-DRAG));
    
    // Reverse thrust
    final float reverseThrustStrength = THRUST * REVERSE_THRUST
        * controllerThrustVector.dot(physicsNode.getLinearVelocity(null)
                             .multLocal(-1).normalizeLocal());
    if (reverseThrustStrength > 0) {
      physicsNode.addForce(physicsNode.getLinearVelocity(null).normalizeLocal()
          .multLocal(-reverseThrustStrength));
    }
  }
}
